
#import "ViewLayout.h"

@implementation ViewLayout

+ (ViewLayout *)viewLayout {
    return [[[[self class] alloc] init] autorelease];
}

- (void)layoutSubviews:(NSArray *)arrangedSubviews ofView:(NSView *)view {
    // For subclasses to override.
}

@end

#define X_PADDING   10.0
#define Y_PADDING   10.0

@implementation CircularViewLayout

- (void)layoutSubviews:(NSArray *)arrangedSubviews ofView:(NSView *)view {
    NSRect box = NSInsetRect([view bounds], X_PADDING, Y_PADDING);
    NSSize maxSize = NSMakeSize(0.0, 0.0);
    for (NSView *subview in arrangedSubviews) {
        NSRect frame = [subview frame];
        maxSize.width = MAX(maxSize.width, frame.size.width);
        maxSize.height = MAX(maxSize.height, frame.size.height);
    }
    CGFloat halfMaxWidth = 0.5 * maxSize.width;
    CGFloat halfMaxHeight = 0.5 * maxSize.height;
    CGFloat radiusInset = sqrt(halfMaxWidth * halfMaxWidth + halfMaxHeight * halfMaxHeight);
    NSPoint circleCenter = NSMakePoint(NSMidX(box), NSMidY(box));
    CGFloat circleRadius = MIN(box.size.width, box.size.height) * 0.5 - radiusInset; 

    CGFloat angleInRadians = 0.0;
    CGFloat angleStepInRadians = (2.0 * M_PI) / ((CGFloat)[arrangedSubviews count]);
    for (NSView *subview in arrangedSubviews) {
        NSPoint subviewCenter;
        subviewCenter.x = circleCenter.x + circleRadius * cos(angleInRadians);
        subviewCenter.y = circleCenter.y + circleRadius * sin(angleInRadians);
        NSRect frame = [subview frame];

        // Zero the view's frame rotation momentarily to make positioning the view easier.
        [subview setFrameRotation:0.0];

        // Position the view.
        [subview setFrameOrigin:NSMakePoint(subviewCenter.x - 0.5 * frame.size.width, subviewCenter.y - 0.5 * frame.size.height)];

        // Now rotate the view to the desired angle.  The -setFrameCenterRotation: method, new in Leopard, provides a convenient way to rotate a view about its center point (corresponding to the way that CALayers are rotated).  It adjusts the view's frame origin, together with its frame rotation angle, to achieve the requested rotation about the frame's center.
        CGFloat angleInDegrees = angleInRadians * (180.0 / M_PI);
        [subview setFrameCenterRotation:fmod(angleInDegrees + 270.0, 360.0)];
        angleInRadians += angleStepInRadians;
    }
}

@end

@implementation LoopViewLayout

- (void)layoutSubviews:(NSArray *)arrangedSubviews ofView:(NSView *)view {
    NSRect box = NSInsetRect([view bounds], X_PADDING, Y_PADDING);
    NSSize maxSize = NSMakeSize(0.0, 0.0);
    for (NSView *subview in arrangedSubviews) {
        NSRect frame = [subview frame];
        maxSize.width = MAX(maxSize.width, frame.size.width);
        maxSize.height = MAX(maxSize.height, frame.size.height);
    }
    CGFloat halfMaxWidth = 0.5 * maxSize.width;
    CGFloat halfMaxHeight = 0.5 * maxSize.height;
    CGFloat radiusInset = sqrt(halfMaxWidth * halfMaxWidth + halfMaxHeight * halfMaxHeight);
    NSPoint loopCenter = NSMakePoint(NSMidX(box), NSMidY(box));
    NSSize loopSize = NSMakeSize(0.5 * (box.size.width - 2.0 * radiusInset), 0.5 * (box.size.height - 2.0 * radiusInset));

    CGFloat angle = 0.0;
    CGFloat angleStep = (2.0 * M_PI) / ((CGFloat)[arrangedSubviews count]);
    for (NSView *subview in arrangedSubviews) {
        NSPoint subviewCenter;
        subviewCenter.x = loopCenter.x + loopSize.width * cos(angle);
        subviewCenter.y = loopCenter.y + loopSize.height * sin(2.0 * angle);
        NSRect frame = [subview frame];

        // Zero the view's frame rotation.
        [subview setFrameRotation:0.0];

        // Position the view.
        [subview setFrameOrigin:NSMakePoint(subviewCenter.x - 0.5 * frame.size.width, subviewCenter.y - 0.5 * frame.size.height)];
        angle += angleStep;
    }
}

@end

@implementation ScatterViewLayout

- (void)layoutSubviews:(NSArray *)arrangedSubviews ofView:(NSView *)view {
    NSRect box = NSInsetRect([view bounds], X_PADDING, Y_PADDING);
    NSPoint p;
    for (NSView *subview in arrangedSubviews) {

        // Zero the view's frame rotation momentarily to make positioning the view easier.
        [subview setFrameRotation:0.0];
//		NSSize me;
//		me.width = 100;
//		me.height = 10;
//		[subview scaleUnitSquareToSize:me];
        // Position the view.
        NSRect frame = [subview frame];
        p.x = box.origin.x + drand48() * (box.size.width - frame.size.width);
        p.y = box.origin.y + drand48() * (box.size.height - frame.size.height);
        [subview setFrameOrigin:p];

        // Now rotate the view to the desired angle.  The -setFrameCenterRotation: method, new in Leopard, provides a convenient way to rotate a view about its center point (corresponding to the way that CALayers are rotated).  It adjusts the view's frame origin, together with its frame rotation angle, to achieve the requested rotation about the frame's center.
        [subview setFrameCenterRotation:-30.0 + drand48() * 60.0];
    }
}

@end

@implementation WrappedViewLayout

- (void)layoutSubviews:(NSArray *)arrangedSubviews ofView:(NSView *)view {
    NSRect container = NSInsetRect([view bounds], X_PADDING, Y_PADDING);
    NSPoint p = NSMakePoint(NSMinX(container), NSMaxY(container));
    NSPoint origin;
    CGFloat rowHeight = 0.0;
    for (NSView *subview in arrangedSubviews) {
        NSRect frame = [subview frame];
        if (p.x + frame.size.width > NSMaxX(container)) {
            p.x = NSMinX(container);
            p.y -= rowHeight + Y_PADDING;
            origin.x = p.x;
            origin.y = p.y - frame.size.height;
            p.x += frame.size.width + X_PADDING;
            rowHeight = frame.size.height;
        } else {
            origin.x = p.x;
            origin.y = p.y - frame.size.height;
            p.x += frame.size.width + X_PADDING;
            rowHeight = MAX(rowHeight, frame.size.height);
        }
 
        // Zero the view's frame rotation.
        [subview setFrameRotation:0.0];

        // Position the view.
        [subview setFrameOrigin:origin];
    }
}

@end

